package io.acna.mybatis.plugins;

import io.acna.mybatis.plugins.core.IndieCondition;
import io.acna.mybatis.plugins.core.RowBound;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@Intercepts({@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class})})
public class ConditionHelper implements Interceptor {

    public enum InterceptorType {
        COUNT, SEARCH
    }

    private String connecStr = null;
    private String conditionSql;
    private String strAnd = "AND";
    private String strWhere = "WHERE";
    private IndieCondition condition;
    private QueryCore core;
    private BoundSql boundSql;
    private InterceptorType type;

    public Object intercept(Invocation invocation) throws Throwable {
        RoutingStatementHandler handler = (RoutingStatementHandler) invocation
                .getTarget();
        StatementHandler delegate = (StatementHandler) ReflectUtil
                .getFieldValue(handler, "delegate");
        boundSql = delegate.getBoundSql();
        // 获取参数
        Object obj = boundSql.getParameterObject();
        // 是否拦截标记
        boolean intercept = false;
        // 条件包装体对象
        condition = new IndieCondition();
        // 拦截类型(COUNT总数 或者 SELECT列表查询)
        if (obj instanceof IndieCondition) {
            intercept = true;
            type = InterceptorType.COUNT;
            condition = (IndieCondition) obj;
        } else if (obj instanceof HashMap<?, ?>) {
            @SuppressWarnings("unchecked")
            Map<String, Object> cs = (Map<String, Object>) obj;
            for (Map.Entry<String, Object> c : cs.entrySet()) {
                if (c.getValue() instanceof RowBound) {
                    try {
                        BeanUtils.populate(condition, cs);
                        break;
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
                if (c.getValue() instanceof IndieCondition)
                    condition = (IndieCondition) c.getValue();
            }
            intercept = true;
            type = InterceptorType.SEARCH;
        }
        if (intercept) {
            connecStr = condition.getConnect().toString();
            if (!condition.isWhere())
                strWhere = "AND";
            strAnd = condition.getConnect().getValue();
            conditionSql = "";
            core = new QueryCore();
            core.setCondition(condition);
            core.setConnecStr(connecStr);
            core.setStrAnd(strAnd);
            core.setStrWhere(strWhere);
            core.setType(type);
            core.setBoundSql(boundSql);
            return core.queryCondition(invocation);
        } else {
            return invocation.proceed();
        }

    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties0) {
        System.out.println("loading plugin[ConditionHelper]...");
    }


    /**/

    private static class ReflectUtil {
        /**
         * 利用反射获取指定对象的指定属性
         *
         * @param obj       目标对象
         * @param fieldName 目标属性
         * @return 目标属性的值
         */
        public static Object getFieldValue(Object obj, String fieldName) {
            Object result = null;
            Field field = ReflectUtil.getField(obj, fieldName);
            if (field != null) {
                field.setAccessible(true);
                try {
                    result = field.get(obj);
                } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return result;
        }

        /**
         * 利用反射获取指定对象里面的指定属性
         *
         * @param obj       目标对象
         * @param fieldName 目标属性
         * @return 目标字段
         */
        private static Field getField(Object obj, String fieldName) {
            Field field = null;
            for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz
                    .getSuperclass()) {
                try {
                    field = clazz.getDeclaredField(fieldName);
                    break;
                } catch (NoSuchFieldException e) {
                    // 这里不用做处理，子类没有该字段可能对应的父类有，都没有就返回null。
                }
            }
            return field;
        }

        /**
         * 利用反射设置指定对象的指定属性为指定的值
         *
         * @param obj        目标对象
         * @param fieldName  目标属性
         * @param fieldValue 目标值
         */
        public static void setFieldValue(Object obj, String fieldName,
                                         String fieldValue) {
            Field field = ReflectUtil.getField(obj, fieldName);
            if (field != null) {
                try {
                    field.setAccessible(true);
                    field.set(obj, fieldValue);
                } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

    }
}